#include "stdafx.h"
#include "Model3DRenderer.h"

#include <HSModel/Model3D.h>
#include <HSModel/TransformCoords.h>
#include <HSModel/Triangle3D.h>
#include <HSModel/Point3D.h>

#include <vector>



Model3DRenderer::Model3DRenderer(
  const Model3D& i_model,
  Ogre::SceneManager* ip_scene_manager,
  Ogre::MeshManager* ip_mesh_manager,
  const std::string& i_entity_name,
  const std::string& i_mesh_type,
  const TVector3& i_point,
  bool i_destroy_mesh,
  const double i_angle)
  : m_object_name(i_entity_name)
  , m_mesh_type(i_mesh_type)
  , mp_scene_manager(ip_scene_manager)
  , mp_mesh_manager(ip_mesh_manager),
  m_destroy_mesh(i_destroy_mesh)
  {
  using namespace Ogre;

  std::string mesh_name = i_mesh_type + "MESH";
  if (!ip_scene_manager->hasManualObject(i_mesh_type))
    {
    // Create Manual object
    ManualObject* p_object = ip_scene_manager->createManualObject(i_mesh_type);
    p_object->begin(i_model.GetMaterialName(), RenderOperation::OT_TRIANGLE_LIST);

    for (auto it = i_model.Triangles().begin(); it != i_model.Triangles().end(); ++it)
      {
      for (size_t i = 0; i < 3; ++i)
        {
        TVector3 pt = Coords::WorldToUI(it->GetPoint(i));
        p_object->position(pt.X(), pt.Y(), pt.Z());

        // normal vector -> N = {n, m, l}
        TVector3 norm(0, 1, 0);

        if(i_mesh_type == "LANDSCAPE")
          {
          norm = it->GetPointNormal(i);
          }
        
        p_object->normal(norm.X(), norm.Y(), norm.Z());  

        p_object->textureCoord(it->GetPointUV(i).X(), it->GetPointUV(i).Y());
        }
      }
    p_object->end();  
    p_object->convertToMesh(mesh_name);
    }

  Ogre::Entity* p_ent_obj = ip_scene_manager->createEntity(m_object_name, mesh_name);
  // Add object to scene
  Ogre::SceneNode* p_landscape_node;
  if (ip_scene_manager->hasSceneNode(m_object_name))
    p_landscape_node = ip_scene_manager->getSceneNode(m_object_name);
  else
    p_landscape_node = ip_scene_manager->getRootSceneNode()->createChildSceneNode(m_object_name);
  p_landscape_node->setPosition(i_point.X(), i_point.Y(), i_point.Z());
  p_landscape_node->setOrientation(Ogre::Quaternion(Ogre::Degree(i_angle), Ogre::Vector3::UNIT_Y));

  //shadows from ground
  p_ent_obj->setCastShadows(true);

  p_landscape_node->attachObject(p_ent_obj);
  }

Model3DRenderer::~Model3DRenderer()
  {
  if (mp_scene_manager->hasEntity(m_object_name))
    {
    auto entity = mp_scene_manager->getEntity(m_object_name);
    auto parent = entity->getParentSceneNode();
    parent->detachObject(entity);
    mp_scene_manager->destroyEntity(entity->getName());
    mp_scene_manager->destroySceneNode(parent->getName());
    }
  if (m_destroy_mesh && mp_scene_manager->hasManualObject(m_mesh_type))
    {
    auto object = mp_scene_manager->getManualObject(m_mesh_type);
    mp_scene_manager->destroyManualObject(object);
    mp_mesh_manager->unload(m_mesh_type + "MESH");
    mp_mesh_manager->remove(m_mesh_type + "MESH");
    }
  }

std::string Model3DRenderer::GetObjectName() const
  {
  return m_object_name;
  }

void Model3DRenderer::SetNodePosition(const TVector3& i_point)
  {
  Ogre::Node* p_landscape_node = mp_scene_manager->getRootSceneNode()->getChild(m_object_name);
  p_landscape_node->setPosition(i_point.X(), i_point.Y(), i_point.Z());
  }

void Model3DRenderer::SetNodeOrientation(const double i_angle)
  {
  Ogre::Node* p_landscape_node = mp_scene_manager->getRootSceneNode()->getChild(m_object_name);
  p_landscape_node->setOrientation(Ogre::Quaternion(Ogre::Degree(i_angle), Ogre::Vector3::UNIT_Y));
  }
